<?php
/**
 * 精灵
 * 
 * Created	: 2011-01-24
 * Modified : 2011-01-24
 * @author  : 陈立强
 */
class Elf {
	
	public static $cfg = null;
	public static $cfgName = 'elf/elf';
	public static $attribute = array();
	
	/**
	 * 类中全局使用的变量定义成类属性
	 */
	public static $skillCfg = null;
	
	/**
	 * 战斗过程使用的类属性
	 */
	private static $fel = null;// fight_elf_list
	private static $fml = null;// fight_monser_list
	private static $charCfg = null;// 精灵性格配置
	private static $bout = null;// 战斗进行的第X个回合
	private static $status_list = array(
		'add_atk' => 0,
		'add_def' => 0,
		'add_spe_atk' => 0,
		'add_spe_def' => 0,
		'add_spd' => 0,
		'add_sta' => 0,
	);
	
	/**
	 * 创建(克隆)生成一个精灵
	 * @param $uid
	 * @param $elf_id 精灵模板ID
	 * @param $arr 附加参数
	 */
	public static function create($uid, $elf_id, $attr=array())
	{
		global $DB, $L, $G;
		
		$elf_id = (int)$elf_id;
		$cfgInfo = self::$cfg[$elf_id];
		
		// 判断基因库是否达到百分百完整度
		$sql = 'SELECT progress FROM `elf_gene_library` WHERE elf_id='.$elf_id;
		$progress = $DB->getValue($sql);
		$progress = round($progress/100, 2);
		if ($progress < 100) {
			return array(
				'val' => false,
				'msg' => $L['elf_gene_progress_not_full']
			);
		}
		
		
		// 是否成功
//		$isCloneSuccess = getRandResult($cfgInfo['clone_success_rate']);
//		if (!$isCloneSuccess) {
//			return array(
//				'val' => false,
//				'msg' => $L['clone_elf_failure']
//			);
//		}
		
		$attr1 = $cfgInfo['attr1'];
		$attr2 = $cfgInfo['attr2'];
		// 默认技能
		$defaultSkillId = $cfgInfo['default_skill_id'];
		
		// 随机获取精灵的品质
		$quality = getRandResult($G['elf_quality_rand_rate']);
		
		// 性格
		$character = C('elf/character');
		$char = array_rand($character);
		$charRevise = $character[$char];
		
		// 默认等级1级
		if (isset($attr['lvl'])) {
			$lvl = $attr['lvl'];
		} else {
			$lvl = 1;
		}
		
		// 属性种族值
		$raceCfg = C('elf/race');
		$star_grade		= $cfgInfo['star_grade'];
		$race_sta		= $raceCfg[$star_grade['sta']][$quality];
		$race_atk		= $raceCfg[$star_grade['atk']][$quality];
		$race_def		= $raceCfg[$star_grade['def']][$quality];
		$race_spe_atk	= $raceCfg[$star_grade['spe_atk']][$quality];
		$race_spe_def	= $raceCfg[$star_grade['spe_def']][$quality];
		$race_spd		= $raceCfg[$star_grade['spd']][$quality];
		// 属性能力值
		$sta	= floor($G['elf_init_val']['sta']
						+ ( ($cfgInfo['grow_up_value'] + $race_sta*2) * $lvl/100 ) 
						* $charRevise['sta']);
		$atk	= floor($G['elf_init_val']['atk']
						+ ( ($cfgInfo['grow_up_value'] + $race_atk*2) * $lvl/100 ) 
						* $charRevise['atk']);
		$def	= floor($G['elf_init_val']['def']
						+ ( ($cfgInfo['grow_up_value'] + $race_def*2) * $lvl/100 ) 
						* $charRevise['def']);
		$spe_atk = floor($G['elf_init_val']['spe_atk']
						+ ( ($cfgInfo['grow_up_value'] + $race_spe_atk*2) * $lvl/100 )
						* $charRevise['spe_atk']);
		$spe_def = floor($G['elf_init_val']['spe_def']
						+ ( ($cfgInfo['grow_up_value'] + $race_spe_def*2)* $lvl/100 ) 
						* $charRevise['spe_def']);
		$spd 	= floor($G['elf_init_val']['spd']
						+ ( ($cfgInfo['grow_up_value'] + $race_spd*2) * $lvl/100 )
						* $charRevise['spd']);
		
		$DB->beginTransaction();
		
		$data = array(
			'telf_id'			=> $elf_id,
			'uid'				=> $uid,
			'title'				=> $cfgInfo['title'],
			'character'			=> $char,
			'lvl'				=> 1,
			'exp'				=> 0,
			'attr1'				=> $attr1,
			'attr2'				=> $attr2,
			'default_skill_id'	=> $defaultSkillId,
			'skills'			=> '',
			'grow_up_value'		=> $cfgInfo['grow_up_value'],
			'race_sta'			=> $race_sta,
			'race_atk'			=> $race_atk,
			'race_def'			=> $race_def,
			'race_spe_atk'		=> $race_spe_atk,
			'race_spe_def'		=> $race_spe_def,
			'race_spd'			=> $race_spd,
			'sta'				=> $sta,// 初始当前体力能力值等于能力值最大值
			'max_sta'			=> $sta,
			'atk'				=> $atk,
			'def'				=> $def,
			'spe_atk'			=> $spe_atk,
			'spe_def'			=> $spe_def,
			'spd'				=> $spd,
			'atk_hit'			=> 0,
			'atk_dodge'			=> 20,//精灵初始值为20
			'atk_might'			=> 0,
			'atk_resist'		=> 0,
			'atk_crit_rate'		=> 0,
			'atk_crit_might'	=> 0,
			'atk_crit_resist'	=> 0,
			'spe_atk_hit'		=> 0,
			'spe_atk_dodge'		=> 20,//精灵初始值为20
			'spe_atk_might'		=> 0,
			'spe_atk_resist'	=> 0,
			'spe_atk_crit_rate'	=> 0,
			'spe_atk_crit_might'=> 0,
			'spe_atk_crit_resist'=> 0,
		);
		$elf_id = $DB->insert('elf', $data);
		$result['val'] = (boolean)$elf_id;
		if ($elf_id) {
			$DB->commit();
			$result['data'] = array(
				'elf_id' => $elf_id
			);
		} else {
			$DB->rollBack();
			$result['msg'] = $L['Failure_Insert'];
			$str = var_export($DB->errors, true);
			// 记录错误日志
			Log::save('elf_create', $str);
		}
		
		
		return $result;
	}
	
	/**
	 * 精灵升级
	 * @param int $uid
	 * @param int $elf_id
	 */
	public static function lvlUp($uid, $elf_id)
	{
		global $DB, $L, $G;
		
		$elf_id = (int)$elf_id;
		
		$cfgInfo = self::$cfg[$elf_id];
		
		return $result;
	}
	
	/**
	 * 给精灵增加辅助状态
	 * @param array $info
	 * @param string $status_type
	 */
	private static function addSkillStatus($info, $status_type='status_list')
	{
		global $DB, $L, $G;
		$skillInfo = $info['skill_info'];
		$skillId = $info['skill_id'];
		
		// 精灵附加状态
		if ($info['type'] == 'elf') {
			$info = &self::$fel[$info['list_key']];
		} else {
			$info = &self::$fml[$info['list_key']];
		}
		
		$add_value = $skillInfo['param1'] 
			+ ($info['skills'][$skillId]-1) * $skillInfo['param2'];
		// 如果是增加普攻
		if (in_array('atk', $skillInfo['add_status_list'])) {
			$info[$status_type]['add_atk'] = isset($info[$status_type]['add_atk'])
				? max($info[$status_type]['add_atk'], $add_value)
				: $add_value; 
		}
		// 如果是增加普防
		if (in_array('def', $skillInfo['add_status_list'])) {
			$info[$status_type]['add_def'] = isset($info[$status_type]['add_def'])
				? max($info[$status_type]['add_def'], $add_value)
				: $add_value;
		}
		// 如果是增加特攻
		if (in_array('spe_atk', $skillInfo['add_status_list'])) {
			$info[$status_type]['spe_atk'] = isset($info[$status_type]['spe_atk'])
				? max($info[$status_type]['spe_atk'], $add_value)
				: $add_value;
		}
		// 如果是增加特防
		if (in_array('spe_def', $skillInfo['add_status_list'])) {
			$info[$status_type]['add_spe_def'] = isset($info[$status_type]['add_spe_def'])
				? max($info[$status_type]['add_spe_def'], $add_value)
				: $add_value;
		}
		// 如果是增加速度
		if (in_array('spd', $skillInfo['add_status_list'])) {
			$info[$status_type]['add_spd'] = isset($info[$status_type]['add_spd'])
				? max($info[$status_type]['add_spd'], $add_value)
				: $add_value;
		}
		// 如果是增加体力值
		if (in_array('sta', $skillInfo['add_status_list'])) {
			if ($status_type == '_status_list') {
				$info['sta'] += $add_value;
			} else {
				$info[$status_type]['add_sta'] = isset($info[$status_type]['add_sta'])
					? max($info[$status_type]['add_sta'], $add_value)
					: $add_value;
			}
		}
		// 如果是属性技能伤害
		if (isset($skillInfo['add_attr_atk']) && 
				($info['attr1']==$skillInfo['add_attr_atk'] || $info['attr2']==$skillInfo['add_attr_atk'])) {
			$info[$status_type]['add_attr_atk'] = isset($info[$status_type]['add_attr_atk'])
				? max($info[$status_type]['add_attr_atk'], $add_value)
				: $add_value;
		}
		
		return true;
	}
	
	/**
	 * 精灵战斗的每个回合
	 * @param array $info
	 * @param string $debuff
	 */
	private static function addDebuff ($info, $debuff)
	{
		global $DB, $L, $G;
		$cfg = $G['skill_debuff'][$debuff];
		// debuff是否被攻击目标的属性克制(即无效)
		if (in_array($info['attr1'], $cfg['out_ef']) 
					|| in_array($info['attr2'], $cfg['out_ef'])) {
			return false;
		}
		
		$bout = rand($cfg['bout'][0], $cfg['bout'][1]);
		// 倒地状态,回合数保存的是当前回合的数据
		if ($debuff == 'fall_over') {
			$bout = self::$bout;
		}
		
		if (isset($info['debuff_list'])) {
			if ($debuff == 'mortis') {//濒死清除所有的debuff
				$info['debuff_list'] = array('mortis' => 999);
			}
			// 循环判断是否有技能会被当前技能覆盖
			foreach ($info['debuff_list'] as $k=>$v) {
				$_cfg = $G['skill_debuff'][$k];
				if (in_array($debuff, $_cfg['beCovered'])) {
					unset($info['debuff_list'][$k]);
				}
			}
			// 默认同一种状态覆盖自身情况,不叠加
			$info['debuff_list'][$debuff] = $bout;
		} else {
			$info['debuff_list'] = array($debuff => $bout);
		}
		// 更新战斗列表对应精灵/怪物的信息
		if ($info['type'] == 'elf') {
			self::$fel[$info['list_key']] = $info;
		} else {
			self::$fml[$info['list_key']] = $info;
		}
		return true;
	}
	
	/**
	 * 精灵战斗的每个回合
	 * @param array $elfInfo
	 * @param array $defenseElfInfo
	 */
	public static function fightOnce (&$attackerInfo, &$defenderInfo)
	{
		global $DB, $L, $G;
		
		$skillId  = $attackerInfo['skill_id'];
		$skillCfg = self::$skillCfg[$skillId];
		
		$atkDebEffList = array();
		$defDebEffList = array();
	
		// 循环获取防方的debuff情况 
		if (!empty($atkDebEffList['debuff_list'])) {
			// 是否有攻击反馈体力
			foreach ($attackerInfo['debuff_list'] as $debuff => $bout) {
				$cfg = $G['skill_debuff'][$debuff];
				if (!empty($cfg['-hit'])) {
					$atkDebEffList['-hit'] = $cfg['-hit'];
				}
				if (!empty($cfg['-atk'])) {
					$atkDebEffList['-atk'] = $cfg['-atk'];
				}
				if (!empty($cfg['-spe_atk'])) {
					$atkDebEffList['-spe_atk'] = $cfg['-spe_atk'];
				}
			}
		}
	
		// 循环获取防方的debuff情况 
		if (!empty($defenderInfo['debuff_list'])) {
			// 是否有攻击反馈体力
			foreach ($defenderInfo['debuff_list'] as $debuff => $bout) {
				$cfg = $G['skill_debuff'][$debuff];
				if (!empty($cfg['back_sta'])) {
					$defDebEffList['back_sta'] = $cfg['back_sta'];
				}
				if (!empty($cfg['-def'])) {
					$defDebEffList['-def'] = $cfg['-def'];
				}
				if (!empty($cfg['-spe_def'])) {
					$defDebEffList['-spe_def'] = $cfg['-spe_def'];
				}
			}
		}
		
		//--- 当前攻击是否命中
		if (!empty($defenderInfo['cannot_dodge'])) {// 防守方中了不能闪躲的debuff
			$isHit = true;
		} elseif ($skillCfg['type'] == 1) {// 普攻
			$hit = $skillCfg['hit'] + $attackerInfo['atk_hit'] - $defenderInfo['atk_dodge'];
			if (isset($atkDebEffList['-hit'])) {
				$hit -= $atkDebEffList['-hit'];
			}
			$isHit = getRandResult($hit);
		} elseif ($skillCfg['type'] == 2) {// 特攻
			$hit = $skillCfg['hit'] + $attackerInfo['spe_atk_hit'] - $defenderInfo['spe_atk_dodge'];
			if (isset($atkDebEffList['-hit'])) {
				$hit -= $atkDebEffList['-hit'];
			}
			$isHit = getRandResult($hit);
		} else {
			$isHit = true;
		}
		
		if (!$isHit) {
			return array(
				'val' => false,
				'log' => array(
					'hit'			=> false,
					'defense_fail'	=> false,
				)
			);
		}
		
		// 是否有攻击反馈体力
		if (!empty($debuff_effect_list['back_sta'])) {
			$attackerInfo['sta'] += ($defenderInfo['max_sta']*$defDebEffList['back_sta']/100);
		}
	
		if (isset($skillCfg['add_debuff'])) {
			self::addDebuff($defenderInfo, $skillCfg['add_debuff']);
		}
		
		// 当前回合的技能
		$attackSkill  = $attackerInfo['skill_info'];
		$defenseSkill = $defenderInfo['skill_info'];
		
		$attrRevise1 = self::$attribute[$attackerInfo['attr1']][$defenderInfo['attr1']];
		if ($defenderInfo['attr2']) {
			$attrRevise2 = self::$attribute[$attackerInfo['attr1']][$defenderInfo['attr2']];
		} else {
			$attrRevise2 = 1;
		}
		
		$attrRevise = $attrRevise1 * $attrRevise2;
		// 性格修正
		$character = self::$charCfg;
		$charRevise = $character[$attackerInfo['character']];
		
		/**
		 * 判断所有技能的可能性
		 */
		// 普攻技能
		if ($skillCfg['type'] == 1) {
			$skillLvl = $attackerInfo['skills'][$skillId];
			$skillHurt = $skillCfg['param1']+pow($skillLvl-1, $skillCfg['param2']);
			$attackValue = floor(self::getComAttack($attackerInfo, $defenderInfo, $skillHurt, $attrRevise, $atkDebEffList, $defDebEffList));
			$attackType = 1;
		} elseif ($skillCfg['type'] == 2) {// 如果是特攻技能
			$skillLvl = $attackerInfo['skills'][$skillId];
			$skillHurt = $skillCfg['param1']+pow($skillLvl-1, $skillCfg['param2']);
			
			// 特攻伤害
			$attackValue = floor(self::getSpeAttack($attackerInfo, $defenderInfo, $skillHurt, $attrRevise, $atkDebEffList, $defDebEffList));
			$attackType = 2;
		} elseif ($skillCfg['type'] == 3) {// 如果是辅助技能
			$attackType = 0;
			$attackValue = 0;
			if ($skillCfg['skill_target'] == 'self') {// 给自身添加技能
				self::addSkillStatus($attackerInfo);
			} elseif($skillCfg['skill_target'] == 'rand') {// 随机给队友添加状态
				// 随机一名要添加状态的队友,只当前回合有效
				if ($attackerInfo['type'] == 'elf') {
					$key = array_rand(self::$fel);
					self::addSkillStatus(self::$fel[$key], $type='_status_list');
				} else {
					$key = array_rand(self::$fml);
					self::addSkillStatus(self::$fml[$key], $type='_status_list');
				}
			} elseif ($skillCfg['skill_target'] == 'team') {// 给全队所有的队员添加
				if ($attackerInfo['type'] == 'elf') {
					$team = &self::$fel;
				} else {
					$team = &self::$fml;
				}
				foreach ($team as $info) {
					self::addSkillStatus($attackerInfo);
				}
			}
			
			// 使用完辅助删除对应的技能(辅助技能只能使用一次)----------
			if ($attackerInfo['type'] == 'elf') {
				unset(self::$fel[$attackerInfo['list_key']]['skills'][$attackerInfo['skill_id']]);
			} else {
				unset(self::$fml[$attackerInfo['list_key']]['skills'][$attackerInfo['skill_id']]);
			}
		}
		
		if ($attackValue) {
			// debuff状态是否有减少或增加伤害的情况
			if (isset($defenderInfo['debuff_list'])) {
				foreach ($defenderInfo['debuff_list'] as $debuff => $bout) {
					$cfg = $G['skill_debuff'][$debuff];
					if ($cfg['-behurted']) {
						$attackValue = $attackValue*(100-$cfg['-behurted'])/100;
					}
				}
			}
			$defenderInfo['sta'] -= $attackValue;
		}
		
		// 当体力低于10%时自动获得[濒死]debuff
		if ($defenderInfo['sta']/$defenderInfo['max_sta'] < 0.1) {
			self::addDebuff($defenderInfo, 'mortis');
		}
		
		$result['val'] = true;
		if ($defenderInfo['sta'] <= 0) {
			$result['defense_fail'] = true;
		} else {
			$result['defense_fail'] = false;
		}
		$result['defender_sta'] = ($defenderInfo['sta']<0) ? 0 : $defenderInfo['sta'];
		$result['log'] = array (
			'hit'			=> true,
			'attack_type'	=> $attackType,
			'attack_value'	=> $attackValue,
		);
		
		return $result;
	}

	/**
	 * 打野怪
	 * @param int $uid
	 * @param int $elf_id_list 玩家的精灵列表
	 * @param int $data 挑战怪物的地图节点
	 */
	public static function fightMonster($uid, $elf_id_list, $data)
	{
		global $DB, $L, $G;
		
		self::$attribute = C('elf/attribute');
		$raceCfg = C('elf/race');
		self::$charCfg = C('elf/character');
		self::$skillCfg = C('elf/skill');
		
		// 攻击的精灵列表
		$elfList = array();
		self::$fel = &$elfList;
		foreach ($elf_id_list as $elf_id) {
			$sql = 'SELECT * FROM elf WHERE elf_id='.$elf_id;
			$elfInfo = $DB->getValue($sql);
			parse_str($elfInfo['skills'], $elfInfo['skills']);
			foreach ($elfInfo['skills'] as $skillId=>$skillLvl) {
				$skillCfg = self::$skillCfg[$skillId];
				// 全队和随机目标的技能仅在组队状态下才会施放
				if (isset($skillCfg['skill_target']) && $skillCfg['skill_target']!='self') {
					unset($elfInfo['skills'][$skillId]);
				}
			}
			// 精灵配置信息
			$cfgInfo = self::$cfg[$elfInfo['telf_id']];
			$elfInfo['type'] = 'elf';
			$elfInfo['list_key'] = $elf_id;
			// 状态列表
			$elfInfo['status_list'] = self::$status_list;
			// 当前回合有效的状态
			$elfInfo['_status_list'] = self::$status_list;
			// 异常状态
			$elfInfo['debuff_list'] = array();
			$elfList[$elf_id] = $elfInfo;
		}
		
		
		//-- 怪物信息
		$mapElf = C('elf/map_elf');
		$cfg = $mapElf[$data['area']][$data['point']];
		$monsterList = array();
		self::$fml = &$monsterList;
		$elfGeneList = array();
		for ($i=0; $i<$cfg['num']; $i++) {
			$tmp = $cfg['monster_list'][array_rand($cfg['monster_list'])];
			$item = self::$cfg[$tmp['elf_id']];
			$item['elf_id'] = $tmp['elf_id'];
			$item['character'] = $tmp['char'];
			$item['lvl'] = rand($cfg['lvl'][0], $cfg['lvl'][1]);
			$item['atk_hit'] = 0;
			$item['atk_dodge'] = 0;
			$item['atk_might'] = 0;
			$item['atk_resist'] = 0;
			$item['atk_crit_rate'] = 0;
			$item['atk_crit_might'] = 0;
			$item['atk_crit_resist'] = 0;
			$item['spe_atk_hit'] = 0;
			$item['spe_atk_dodge'] = 0;
			$item['spe_atk_might'] = 0;
			$item['spe_atk_resist'] = 0;
			$item['spe_atk_crit_rate'] = 0;
			$item['spe_atk_crit_might'] = 0;
			$item['spe_atk_crit_resist'] = 0;
			// 怪物技能
			$skillLvl = ceil($item['lvl']/10);
			$item['skills'] = array($item['default_skill_id'] => $skillLvl);
			$item = $item + $item['star_grade'];
			$item['max_sta'] = $item['sta'];
			$item['type'] = 'monster';
			$item['list_key'] = $i;
			// 状态列表
			$item['status_list'] = self::$status_list;
			// 当前回合有效的状态
			$item['_status_list'] = self::$status_list;
			// 异常状态
			$item['debuff_list'] = array();
			$monsterList[$i] = $item;
			$elfGeneList[] = $tmp['elf_id'];
		}
		
		
		$log = array();
		
		//-- 循环多回合战斗
		$exitList = array();
		$log = array();
		for ($i=0; $i<300; $i++) {
			self::$bout = $i;
			//-- 每个回合的战斗情况,双方互相攻击一次算一个回合
			
			// 攻击列表,根据攻击速度排出所有精灵和怪物之间的攻击速度
			$attackList = array();
			
			
			
			$speedList = array();
			// 每回合开始对精灵进行数据初始化
			foreach ($elfList as $elf_id=> $elfInfo) {
				// 获取每个精灵本次即将选用的技能
				$skillId = array_rand($elfInfo['skills']);
				$skillInfo = self::$skillCfg[$skillId];
				$elfInfo['skill_info'] = $skillInfo;
				$elfInfo['skill_id'] = $skillId;
				$speed = self::getSpeed($elfInfo);
				$attackList[] = array($elf_id, 'elf', $speed);
				
				// 每个回合之前计算恢复体力 
				if (isset($elfInfo['status_list']['add_sta'])) {
					$elfInfo['sta'] += $elfInfo['status_list']['add_sta'];
				}
				if (isset($elfInfo['_status_list']['add_sta'])) {
					$elfInfo['sta'] += $elfInfo['_status_list']['add_sta'];
				}
				// 每个回合之前开始计算debuff状态 
				if (isset($elfInfo['debuff_list'])) {
					foreach ($elfInfo['debuff_list'] as $debuff=>$bout) {
						if ($bout <= 0) {
							unset($elfInfo['debuff_list'][$debuff]);
							continue;
						}
						// 持续回合数减1(倒地状态例外 )
						if ($debuff != 'fall_over') {
							$elfInfo['debuff_list'][$debuff]--;
						}
						
						$cfg = $G['skill_debuff'][$debuff];
						// 损失体力(百分比按上限来扣除)
						if (isset($cfg['loss_sta'])) {
							$elfInfo['sta'] -= round($elfInfo['max_sta']*$cfg['loss_sta']/100);
						}
						// 是否可以攻击或者闪躲
						if (!empty($cfg['atk'])) {
							$elfInfo['cannot_atk'] = true;
						}
						if (!empty($cfg['dodge'])) {
							$elfInfo['cannot_dodge'] = true;
						}
						if (!empty($cfg['no_act'])) {
							$no_act = getRandResult($cfg['no_act']);
							if ($no_act) {
								$elfInfo['cannot_atk'] = true;
								$elfInfo['cannot_dodge'] = true;
							}
						}
					}
				}
				
				
				$elfList[$elf_id] = $elfInfo;
				$speedList[] = $speed;
			}
			
			// 每回合开始对怪物进行数据初始化
			foreach ($monsterList as $key => $info) {
				$skillId = array_rand($info['skills']);
				$skillInfo = self::$skillCfg[$skillId];
				$info['skill_info'] = $skillInfo;
				$info['skill_id'] = $skillId;
				// 如果辅助技能,从技能列表中移除
				unset($monsterList[$key]['skills'][$skillId]);
				$speed = self::getSpeed($info);
				$attackList[] = array($key, 'monster', $speed);
				
				// 每个回合之前计算恢复体力 
				if (isset($info['status_list']['add_sta'])) {
					$info['sta'] += $info['status_list']['add_sta'];
				}
				if (isset($info['_status_list']['add_sta'])) {
					$info['sta'] += $info['_status_list']['add_sta'];
				}
				// 每个回合之前开始计算debuff状态 
				if (isset($info['debuff_list'])) {
					foreach ($info['debuff_list'] as $debuff=>$bout) {
						if ($bout <= 0) {
							unset($info['debuff_list'][$debuff]);
							continue;
						}
						// 持续回合数减1(倒地状态例外 )
						if ($debuff != 'fall_over') {
							$elfInfo['debuff_list'][$debuff]--;
						}
						$info['debuff_list'][$debuff]--;
						$cfg = $G['skill_debuff'][$debuff];
						// 损失体力(百分比按上限来扣除)
						if (isset($cfg['loss_sta'])) {
							$info['sta'] -= round($info['max_sta']*$cfg['loss_sta']/100);
						}
						// 是否可以攻击或者闪躲
						if (!empty($cfg['atk'])) {
							$info['cannot_atk'] = true;
						}
						if (!empty($cfg['dodge'])) {
							$info['cannot_dodge'] = true;
						}
						if (!empty($cfg['no_act'])) {
							$no_act = getRandResult($cfg['no_act']);
							if ($no_act) {
								$info['cannot_atk'] = true;
								$info['cannot_dodge'] = true;
							}
						}
					}
				}
				
				$monsterList[$key] = $info;
				$speedList[] = $speed;
			}
			// 根据速度倒序决定攻击顺序
			array_multisort($speedList, SORT_DESC, $attackList);
			foreach ($attackList as $k => $v) {
				unset($attackList[$k][2]);
			}
			$log[$i] = array();
			
			
			// 根据攻击顺序循环计算对对手进行攻击的情况
			foreach ($attackList as $k=>$v) {
				unset($v[2]);
				if (in_array($v, $exitList)) continue;
				if ($v[1] == 'elf') {
					$attackerInfo = $elfList[$v[0]];
					$defenderKey  = array_rand($monsterList);
					$defenderInfo = $monsterList[$defenderKey];
					$defenderV    = array($defenderKey, 'monster');
				} else {
					$attackerInfo = $monsterList[$v[0]];
					$defenderKey  = array_rand($elfList);
					$defenderInfo = $elfList[$defenderKey];
					$defenderV    = array($defenderKey, 'elf');
				}
				if (!empty($attackerInfo['cannot_atk'])) {
					continue;
				}
				
				if (isset($attackerInfo['debuff_list']['fall_over']) 
						&& $attackerInfo['debuff_list']['fall_over'] == self::$bout) {
					continue;// 倒地不能进行本回合攻击 
				} elseif ($v[1] == 'elf') {
					unset($elfList[$v[0]]['debuff_list']['fall_over']);
				} else {
					unset($monsterList[$v[0]]['debuff_list']['fall_over']);
				}
				$ret = self::fightOnce($attackerInfo, $defenderInfo);
				$tmp = $ret['log'];
				$tmp['attacker'] = array(
					'type' => $v[1],
					'elf_id' => $attackerInfo['elf_id'],
					'skill_id' => $attackerInfo['skill_id']
				);
				$tmp['defender_sta'] = $ret['defender_sta'];
				$log[$i][] = $tmp;
				// 更新防御方的体力
				if ($defenderV[1] == 'elf') {
					$elfList[$defenderKey]['sta'] = $ret['defender_sta'];
				} else {
					$monsterList[$defenderKey]['sta'] = $ret['defender_sta'];
				}
				
				if ($ret['defense_fail']) {
					$key = array_search($defenderV, $attackList);
					unset($attackList[$key]);
					// 将防守失败的精灵/怪物从本回合攻击队列中移除
					$exitList[] = $defenderV;
					if ($defenderV[1]=='elf') {
						unset($elfList[$defenderV[0]]);
					} else {
						unset($monsterList[$defenderV[0]]);
					}
				}
			}
			// 当前回合结束,所有的精灵和怪物身上的当前回合状态 清空
			foreach (self::$fel as $item) {
				$item['_status_list'] = self::$status_list;
			}
			foreach (self::$fml as $item) {
				$item['_status_list'] = self::$status_list;
			}
			
			// 精灵或怪物全部死亡则退出战斗
			if (empty($elfList) || empty($monsterList)) {
				break;
			}
		}
		
		// 如果是第一次打这种怪,加入到基因库,否则更新基因库完整度
		foreach ($elfGeneList as $monster_elf_id) {
			$elfCfg = self::$cfg[$monster_elf_id];
			$where = ' elf_id='.$monster_elf_id.' and uid='.$uid;
			$sql = 'SELECT egl_id,progress FROM elf_gene_library WHERE '.$where;
			$eglInfo = $DB->getValue($sql);
			$addProgress = 1 * $elfCfg['clone_success_rate'] + rand(-5, 5);
			if ($eglInfo) {
				// 已满 100%就不用再更新
				if ($eglInfo['progress'] < 10000) {
					$sql = 'UPDATE elf_gene_library set progress=progress+'.$addProgress;
					$ret = $DB->exeSql($sql);
				}
			} else {
				if ($addProgress < 0) $addProgress = 0;
				$data = array(
					'elf_id' => $monster_elf_id,
					'uid' => $uid,
					'progress' => $addProgress,
				);
				$ret = $DB->insert('elf_gene_library', $data);
			}
		}
		
		$DB->beginTransaction();
		
		// 更新精灵的体力能力值
		foreach ($elfList as $elf_id=> $elfInfo) {
			$data = array(
				'sta' => $elfInfo['sta']
			);
			$ret = $DB->update('elf', $data);
			if (!$ret) {
				break;
			}
		}
		
		// 战斗结果
		$result['val'] = (bool)$ret;
		if ($ret) {
			$DB->commit();
			$result['data'] = array(
				'log' => $log
			);
		} else {
			$DB->rollBack();
			$result['msg'] = $L['Failure_Insert'];
			$str = var_export($DB->errors, true);
			// 记录错误日志
			Log::save('elf_fight_monster', $str);
		}
		
		// 清空不用的战斗精灵和怪物列表
		self::$fel = null;
		self::$fml = null;
		self::$charCfg = null;
		self::$bout = null;
		unset($elfList, $monsterList);
		
		return $result;
	}
	
	/**
	 * 获取精灵/怪物加技能后的速度
	 * @param array $elfInfo
	 */
	private static function getSpeed($elfInfo)
	{
		global $G;
		
		// 循环获取debuff情况 
		if (!empty($atkDebEffList['debuff_list'])) {
			// 是否有攻击反馈体力
			foreach ($attackerInfo['debuff_list'] as $debuff => $bout) {
				$cfg = $G['skill_debuff'][$debuff];
				if (!empty($cfg['-spd'])) {
					$_spd = $cfg['-spd'];
				}
			}
		} else {
			$_spd = 0;
		}
		
		$skillInfo = $elfInfo['skill_info'];
		$skillId = $elfInfo['skill_id'];
		// 根据配置公式计算技能速度
		$search = array(
						'$baseSpeed',
						'$skillLvl',
						'$param3'
		);
		$replace = array(
						$elfInfo['status_list']['add_spd'] + $skillInfo['spd'], 
						$elfInfo['skills'][$skillId], 
						$skillInfo['param3'],
		);
		$evalStr = str_replace($search, $replace, $G['skill_formula']['speed_formula']);
		$skillSpeed = eval('return '.$evalStr.';');
		// 状态有没有附加的速度 
		$statusSpeed = 0;
		$speed = round($elfInfo['spd'] + $skillSpeed + $statusSpeed) - $_spd;
		return $speed;
	}
	
	/**
	 * 获取一个精灵普攻伤害
	 * @param array $attackerInfo
	 * @param array $defenderInfo
	 * @return int
	 */
	private static function getComAttack($attackerInfo, $defenderInfo, $skillHurt, $attrRevise, $atkDebEffList, $defDebEffList)
	{
		global $G;
		$attackerAtk = $attackerInfo['atk']+$attackerInfo['status_list']['add_atk'];
		// debuff状态有减少普攻
		if (isset($atkDebEffList['-atk'])) {
			$attackerAtk = $attackerAtk * (100 - $atkDebEffList['-atk'])/100;
		}
		// debuff状态有减少普防
		$defenderDef = $defenderInfo['def']+$defenderInfo['status_list']['add_def'];
		if (isset($defDebEffList['-def'])) {
			$defenderDef = $defenderDef * (100 - $defDebEffList['-def'])/100;
		}
		// 波动值
		$randValue = rand(80, 100)/100;
		// 普攻威力
		$comMight = 0;
		// 防守方有没有附加的状态普防
		$defenderInfo['def'] += 0;
		// 普攻伤害减免
		$comMitigate = $defenderDef/($defenderDef+$attackerInfo['lvl']*100+500)
						+ $defenderInfo['atk_resist'];
		// 普攻伤害
		$comAttack = ($attackerAtk + $skillHurt)*$attrRevise*(1+$comMight)*$randValue;
		
		// 是否暴击
		
		
		return $comAttack;
	}
	
	/**
	 * 获取一个精灵特攻伤害
	 * @param array $elfInfo
	 */
	private static function getSpeAttack($attackerInfo, $defenderInfo, $skillHurt, $attrRevise, $atkDebEffList, $defDebEffList)
	{
		global $G;
		$attackerSpeAtk = $attackerInfo['spe_atk'] + $attackerInfo['status_list']['add_spe_atk'];
		$defenderSpeDef = $defenderInfo['spe_def'] + $defenderInfo['status_list']['add_spe_def'];
		// debuff状态有减少普攻
		if (isset($atkDebEffList['-spe_atk'])) {
			$attackerSpeAtk = $attackerSpeAtk * (100 - $atkDebEffList['-spe_atk'])/100;
		}
		// debuff状态有减少普防
		$defenderDef = $defenderInfo['def']+$defenderInfo['status_list']['add_def'];
		if (isset($defDebEffList['-spe_def'])) {
			$defenderDef = $defenderDef * (100 - $defDebEffList['-spe_def'])/100;
		}
		// 波动值
		$randValue = rand(80, 100)/100;
		// 特攻威力
		$speMight = 0;
		// 防守方有没有附加的状态特防
		$defenderInfo['def'] += 0;
		// 特攻伤害减免
		$comMitigate = $defenderSpeDef/($defenderSpeDef + $attackerInfo['lvl']*100+500)
						+ $defenderInfo['spe_atk_resist'];
		// 特攻伤害
		$speAttack = ($attackerSpeAtk + $skillHurt)*$attrRevise*(1+$speMight)*$randValue;
		
		return $speAttack;
	}
	
	/**
	 * 获取所有精灵技能列表(包括已学习和未学习的)
	 * @param $uid
	 * @param $elf_id
	 */
	public static function getSkillList($uid, $elf_id)
	{
		global $DB, $L;
		$list = C('elf/skill');
		
		
		
		return $list;
	}
	
	/**
	 * 精灵增加经验
	 * @param int $uid
	 * @param int $skillId
	 * @param int $exp
	 */
	public static function addExp($uid, $skillId, $exp)
	{
		global $DB, $L;

		$uid     = (int)$uid;
		$skillId = (int)$skillId;
		$exp     = (int)$exp;

		$skillList = C('elf_exp');
		$skillInfo = $skillList[$skillId];

		$sql  = 'SELECT * FROM '.self::$tbl.' WHERE uid='.$uid.' and skill_id='.$skillId;
		$info = $DB->getValue($sql);

		$skillExpCfg = C('skill_exp');
		$maxExp = $skillExpCfg[$info['skill_lvl']];
		$maxLvl = $skillExpCfg[$info['skill_max_lvl']];

		$skillLvl = $info['skill_lvl'];
		$skillExp = $info['skill_exp'] + $exp;

		// 满经验了
		if ($skillLvl == $maxLvl && $skillExp > $maxExp) {
			$newExp = $maxExp;
		} elseif ($skillExp > $maxExp) {
			$skillExp -= $maxExp;
			$skillLvl++;
			for ($i=$skillLvl; $i<=$skillInfo['max_lvl']; $i++) {
				if ($skillExp < $skillExpCfg[$i]) {
					break;
				} else {
					$skillExp -= $skillExpCfg[$i];
					$skillLvl++;
				}
			}
		}
		
		$data = array(
			'skill_lvl' => $skillLvl,
			'skill_exp' => $skillExp
		);
		$where = 'us_id='.$info['us_id'];
		$ret = $DB->update(self::$tbl, $data, $where);
		$result['val'] = (boolean)$ret;
		if ($ret) {
			$result['data'] = $data;
		} else {
			$result['msg'] = $L['Failure'];
			// 记录错误日志
			Log::save('user_add_exp', $data);
		}
		return $result;
	}
	
	/**
	 * 学习精灵技能
	 * @param int $uid 用户ID
	 * @param int $skillId 精灵技能ID
	 */
	public static function studySkill($uid, $skillId)
	{
		global $DB, $L;
		$skillId = (int)$skillId;
		$where = 'uid='.$uid;
		$sql = 'SELECT skill_id FROM user_elf_skills WHERE '.$where;
		$studiedList = $DB->getList($sql,null,0,0,true);
		
		if (in_array($skillId, $studiedList)) {
			return array(
				'val' => false,
				'msg' => $L['elf_skill_had_studied']
			);
		}
		
		// 技能学习的前缀技能是否已学习
		$skillCfg = C('elf/skill');
		$skillCfg = $skillCfg[$skillId];
		if ($skillCfg['pre_skill'] && !in_array($skillCfg['pre_skill'], $studiedList)) {
			return array(
				'val' => false,
				'msg' => $L['pre_skill_hasnot_studied']
			);
		}
		
		// 冒险等级是否达到要求
		$userInfo = User::read($uid);
		if ($userInfo['venture_lvl'] < $skillCfg['need_venture_lvl']) {
			return array(
				'val' => false,
				'msg' => $L['venture_lvl_lower_skill_require']
			);
		}
		
		// 金钱是否足够
		
		
		$studiedList[] = $skillId;
		$studiedList = join(',', $studiedList);
		
		$DB->beginTransaction();
		
		$data = array(
			'uid'		=> $uid,
			'skill_id'	=> $skillId,
			'lvl'		=> 1,
			'end_cd_time' => $skillCfg['cd_time']
		);
		$ret = $DB->insert('user_elf_skills', $data);
		
		$result['val'] = (bool)$ret;
		if ($ret) {
			$DB->commit();
		} else {
			$DB->rollBack();
			$result['msg'] = $L['Failure_Insert'];
			$str = var_export($DB->errors, true);
			// 记录错误日志
			Log::save('elf_study_skill', $str);
		}
		
		return $result;
	}
	
	/**
	 * 将玩家学习的技能赋予指定的精灵
	 * @param int $uid 用户ID
	 * @param int $skillId 技能ID
	 * @param int $elf_id 要学习该技能的精灵
	 */
	public static function indueSkill($uid, $skillId, $elf_id)
	{
		global $DB, $L, $G;
		
		$skillId = (int)$skillId;
		$elf_id  = (int)$elf_id;
		
		// 玩家是否已经学习了技能
		$where = 'uid='.$uid.' and skill_id='.$skillId;
		$sql = 'SELECT skill_id FROM user_elf_skills WHERE '.$where;
		$skill = $DB->getValue($sql);
		if (!$skill) {
			return array(
				'val' => false,
				'msg' => $L['elf_skill_hadnot_studied']
			);
		}
		
		// 精灵是不是属于该玩家
		$sql = 'SELECT * from elf WHERE elf_id='.$elf_id;
		$elfInfo = $DB->getValue($sql);
		if ($elfInfo['uid'] != $uid) {
			return array(
				'val' => false,
				'msg' => $L['elf_is_not_belong_to_user']
			);
		}
		
		parse_str($elfInfo['skills'], $elfInfo['skills']);
		// 精灵是否已经学习了该技能
		if (in_array($skillId, $elfInfo['skills'])) {
			return array(
				'val' => false,
				'msg' => $L['elf_had_studied_this_skill']
			);
		}
		
		// 精灵拥有的技能数是否已经达到上限
		if (sizeof($elfInfo['skills']) >= $G['elf_max_skill_num']) {
			return array(
				'val' => false,
				'msg' => $L['elf_skills_is_max']
			);
		}
		
		self::$skillCfg = C('elf/skill');
		$skillCfg = self::$skillCfg[$skillId];
		
		// 精灵技能不能全部是辅助技能
		if ($skillCfg['type'] == 3) {
			$allAuxiliarySkill = true;
			foreach ($elfInfo['skills'] as $skillId=>$skillLvl) {
				if (self::$skillCfg[$skillId]['type']!=3) {
					$allAuxiliarySkill = false;
					break;
				}
			}
			if ($allAuxiliarySkill) {
				return array(
					'val' => false,
					'msg' => $L['elf_skill_cannot_auxiliary']
				);
			}
		}
		
		// 技能属性是否和精灵一致
		if ($skillCfg['attr']!=$elfInfo['attr1'] && $skillCfg['attr']!=$elfInfo['attr2']) {
			return array(
				'val' => false,
				'msg' => $L['elf_skill_attr_not_match']
			);
		}
		
		$elfInfo['skills'][$skillId] = 1;
		
		$DB->beginTransaction();
		
		$data = array(
			'skills' => join(',', $elfInfo['skills'])
		);
		$ret = $DB->update('elf', $data, 'elf_id='.$elf_id);
		
		$result['val'] = (bool)$ret;
		if ($ret) {
			$DB->commit();
		} else {
			$DB->rollBack();
			$result['msg'] = $L['Failure_Update'];
			$str = var_export($DB->errors, true);
			// 记录错误日志
			Log::save('elf_study_skill', $str);
		}
		
		return $result;
		
	}
}










